#ifndef _INCLUDE_CLASS_WXEX_LCD_BASE_H_
#define _INCLUDE_CLASS_WXEX_LCD_BASE_H_

//=======================================================================//
//= Include files.													    =//
//=======================================================================//
#include <wx\panel.h>
#include <wx\dcbuffer.h>
#include <wx\colour.h>

//=======================================================================//
//= Marco declare.                                                      =//
//=======================================================================//
#define WX_LCD_DEFAULT_WIDTH_PIX					(128)
#define WX_LCD_DEFAULT_HEIGHT_PIX					(64)
#define WX_LCD_DEFAULT_GRID_VISIBLE					(true)
#define WX_LCD_PIX_SIZE_MIN							(3)
#define WX_LCD_PIX_SIZE_MIN_WITH_GRID				(4)
#define WX_LCD_BORDER_WIDTH							(5)
#define WX_LCD_PIX_RGB(ARGB)						((0x00FFFFFF) & (ARGB))
#define wxDefaultLCDPixelUnitSize					(wxSize(2, 2))

//=======================================================================//
//= Global variable declare.										    =//
//=======================================================================//
extern const wxSize	wxDefaultSizeInPixel;

//=======================================================================//
//= Class declare.                                                      =//
//=======================================================================//
class wxLCDBuffer
{
private:
    unsigned int**				m_ppuiDisplayBuffer;
    wxSize						m_clsBufferSize;

    unsigned int**				_createNewDisplayBuffer(int iWidth, int iHeight);
    void						_cleanDisplayBuffer(void);
    void         				_freeDisplayBuffer(unsigned int** ppuiDisplayBuffer);

public:
								wxLCDBuffer(const wxSize& clsSizeInPixel = wxDefaultSizeInPixel);
								~wxLCDBuffer(void);
    void						Resize(int iHorizontalPixelNumber, int iVerticalPixelNumber);
    void						Resize(const wxSize& clsNewSize);
    void						CopyForm(const wxLCDBuffer& clsSourceBuffer);
    const wxSize&				GetBufferSize(void) const               {return m_clsBufferSize;}
    unsigned int				GetData(int iPosX, int iPosY);
    void						SetData(int iPosX, int iPosY, unsigned int uiARGB);
    const unsigned int**		GetData(void) const                     {return (const unsigned int**)m_ppuiDisplayBuffer;}
    void						Clear(void)                             {_cleanDisplayBuffer();}
};

class wxLCDBase
: public wxWindow
{
    DECLARE_EVENT_TABLE();

private:
    wxClientDC					m_clsCDC;
    wxPen						m_clsPen;
    wxBrush						m_clsBrush;
    wxColour					m_clsGridColor;
    wxSize						m_clsSizeInPixel;
    wxSize						m_clsPixelUnitSize;
    bool						m_bGridVisible;
    wxLCDBuffer                 m_clsDisplayBuffer;
    wxCriticalSection			m_clsDisplayBufferCS;
    void						(wxLCDBase::*m_pfDrawPoint)(wxDC& clsDCObject, int iPosX, int iPosY, const wxSize& clsPixelSize);
    bool						m_bIsOK;
    int							m_iBorderWidth;

    void						_getBestSize(wxSize& clsBestSize) const;
    void						_setMinClientSize(void);
    inline void					_drawPointSinglePixel(wxDC& clsDCObject, int iPosX, int iPosY, const wxSize& clsPixelSize);
    inline void					_drawPointMultiplePixel(wxDC& clsDCObject, int iPosX, int iPosY, const wxSize& clsPixelSize);
    inline void					_drawPointMultiplePixelWithGrid(wxDC& clsDCObject, int iPosX, int uiPosY, const wxSize& clsPixelSize);
    inline void					_releaseDC(wxMemoryDC& clsCDCObject)        {clsCDCObject.SetBrush(wxNullBrush);clsCDCObject.SetPen(wxNullPen);}
    inline void					_prepareDC(wxMemoryDC& clsCDCObject)        {clsCDCObject.SetBrush(m_clsBrush);clsCDCObject.SetPen(m_clsPen);}
    inline void					_releaseDC(wxClientDC& clsCDCObject)        {clsCDCObject.SetBrush(wxNullBrush);clsCDCObject.SetPen(wxNullPen);}
    inline void					_prepareDC(wxClientDC& clsCDCObject)        {clsCDCObject.SetBrush(m_clsBrush);clsCDCObject.SetPen(m_clsPen);}
	inline void					_setDCColor(const wxColour& clsColour)      {m_clsPen.SetColour(clsColour);m_clsBrush.SetColour(clsColour);}
    void						_cleanDisplayBuffer(void);
    bool						_screenShot(wxBitmap& clsBitmap);
    void						_enterPaintCriticalSection(void)            {m_clsDisplayBufferCS.Enter();}
    void						_leavePaintCriticalSection(void)            {m_clsDisplayBufferCS.Leave();}

protected:
    // Event callback function.
    virtual void				OnPaint(wxPaintEvent &clsEvent);
    virtual void				OnEraseBackGround(wxEraseEvent &clsEvent)	{/* Do nothing. */}
    virtual void				OnKeyDown(wxKeyEvent& clsEvent);
    virtual void				OnSetFocus(wxFocusEvent& clsEvent);

public:
    // Constructor/Destructor
								wxLCDBase(	wxWindow *pclsParent, wxWindowID iWinID = wxID_ANY,
											const wxPoint& clsPosition = wxDefaultPosition,
											const wxSize& clsSizeInPixel = wxDefaultSizeInPixel,
											const wxString& cstrName = wxT("LCD Base"));
								~wxLCDBase(void);
    // Public interface
    void						SetBorderWidth(int iBorderWidth);
    int							GetBorderWidth(void)
    {
        return m_iBorderWidth;
    }
    void						SetHorizontalPixelNumber(int iHorizontalPixelNumber);
    void						SetVerticalPixelNumber(int iVerticalPixelNumber);
	virtual void				SetPixelNumber(int iHorizontalPixelNumber, int iVerticalPixelNumber);
	virtual void				SetPixelNumber(const wxSize& clsNewSizeInPixelUnit);
    int							GetHorizontalPixelNumber(void) const;
    int							GetVerticalPixelNumber(void) const;
    virtual void				GetPixelNumber(int* piHorizontalPixelNumber, int* piVerticalPixelNumber);
    virtual const wxSize&		GetPixelNumber(void)						{return m_clsSizeInPixel;}
    void						SetPixelUnitSize(const wxSize& clsPixelUnitSize);
    void						SetPixelUnitSize(int iPixelUnitWidth, int iPixelUnitHeight);
    const wxSize&				GetPixelUnitSize(void) const                {return m_clsPixelUnitSize;}
    void						SetGridVisibled(bool bGridVisible);
    bool						GetGridVisibled(void) const;
    void						SetGridColor(const wxColor& clsColor);
    wxColor&					GetGridColor(void);
    void						SetPixelUnitColor(int iPosX, int iPosY, const wxColor& clsColor);
    void						DrawPixel(int iPosX, int iPosY, const wxColor& clsColor);
    void						FillRect(int iPosX, int iPosY, int iWidthPix, int iHeightPix, const wxColour& clsColour);
    unsigned int				GetPixelUnitColor(int iPosX, int iPosY);
    void						RefreshDisplay(void);
    void						FillColour(const wxColour& clsNewColour);
    void						ReplaceColour(const wxColour& clsOldColour, const wxColour& clsNewColour);
    bool						SaveScreenshot(const wxString& strFilePath);
    bool						CopyScreenshot(void);
    bool						IsOK(void)                                  {return m_bIsOK;}
    virtual wxSize				DoGetBestClientSize(void) const;
    virtual wxSize				DoGetBestSize(void) const;
    virtual void            	FitBestSize(void);
};

#endif // _INCLUDE_CLASS_WXEX_LCD_BASE_H_
